using System;
using System.Globalization;
using System.Text;
// used for merge fieldName replacement
using System.Data;
using System.Collections;
using System.Collections.Specialized;

namespace Behemoth {

	/// <summary>
	/// StringTools is a static library of useful string functions.
	/// There are more where this came from, including some for "unsafe"
	/// string manipulations, scrambling/memory obfuscation (gov format),
	/// and SecureString marshalling ofr .NET 2.0. I will import these
	/// as needed and when I have time. - Tom Carpe 3/15/07
	/// </summary>
	public class StringTools {

    private StringTools() {}

    /// <summary>
    /// Provides support for a "shorthand" function similar to 
    /// string.IsNullOrEmpty that is provided in .NET 2.0.
    /// </summary>
    /// <param name="test"></param>
    /// <returns></returns>
    public static bool IsNullOrEmpty(string test) {
#if __DotNet2__
      return string.IsNullOrEmpty(test);
#else
      return (test == null || test == string.Empty);
#endif
    }

    /// <summary>
    /// This function takes a string, breaks it into individual words and
    /// re-cases those words based on standard English rules for capitalizing 
    /// proper names. Includes support for "Mc", "Mac", and apostrophies like 
    /// "O'" and "D'".
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public static string ProperCase(string name) {
      string[] prefixes = new string[] { "Mc", "Mac" };
      string casedName = string.Empty;
      bool capNextChar = true;
      for (int i = 0; i < name.Length; i++) {
        if (capNextChar)
          casedName += char.ToUpper(name[i]);
        else
          casedName += char.ToLower(name[i]);
        capNextChar = (!char.IsLetterOrDigit(name[i])); // char.IsWhiteSpace(name[i]) || name[i] == '\'
        foreach (string prefix in prefixes) {
          if (casedName.EndsWith(prefix))
            capNextChar = true;
        }
      }
      return casedName;
    }

    /// <summary>
    /// A very basic and error prone way to find the text that is between two "bookend" strings.
    /// If you want a real routine, use RegEx.
    /// </summary>
    /// <param name="searchText"></param>
    /// <param name="atStart"></param>
    /// <param name="atEnd"></param>
    /// <returns></returns>
    public static string LookForInnerText(string searchText, string atStart, string atEnd) {
      int start = searchText.IndexOf(atStart);
      if (start >= 0) {
        start += atStart.Length;
        int end = searchText.IndexOf(atEnd, start);
        if (end >= 0) {
          int length = end - start;
          return searchText.Substring(start, length);
        }
      }
      return string.Empty;
    }

    /// <summary>
    /// For all I know the .NET framework has something in it that can do this... but
    /// Turns escaped sequences like \r\n into their character-code equivalents.
    /// </summary>
    /// <param name="text">Escaped text string</param>
    /// <returns>Converted string with unescaped charaters.</returns>
    public static string ReplaceEscapeSequences(string text) {
      StringBuilder sb = new StringBuilder();
      // There is an Orwellian joke here... ;-P
      for (int unGood = 0; unGood < text.Length; ++unGood) {
        if (text[unGood] == '\\' && unGood < text.Length - 1) { // not the last character
          char nextChar = text[++unGood];
          switch (nextChar) {
            case 't':
              sb.Append('\t');
              break;
            case 'r':
              sb.Append('\r');
              break;
            case 'n':
              sb.Append('\n');
              break;
            case '\\':
              sb.Append('\\');
              break;
            default:
              throw new ArgumentException(
                string.Format(
                  CultureInfo.CurrentCulture,
                  "Unrecognized character escape sequence: '\\{0}'",
                  nextChar));
          }
        } else
          sb.Append(text[unGood]);
      }
      return sb.ToString();
    }

    private const string MergeDelimeter = "%";

    public static string MergeFields(IDictionary fields, string text) {
      foreach (DictionaryEntry item in fields) {
        text = text.Replace(
          MergeDelimeter + item.Key.ToString() + MergeDelimeter,
          item.Value.ToString()
        );
      }
      return text;
    }
    public static string MergeFields(DataRow fieldsRow, string text) {
      foreach (DataColumn col in fieldsRow.Table.Columns) {
        string key = col.ColumnName;
        string value = fieldsRow.ItemArray[col.Ordinal].ToString();
        text = text.Replace(MergeDelimeter + key + MergeDelimeter, value);
      }
      return text;
    }

	} // clas

} // namespace
